#ifndef AVL_NODE_H_
#define AVL_NODE_H_

enum NodeType {LEFT = -1, PARENT = 0, RIGHT = 1};

template <typename T>
class AVLNode {
public:
	// C-tors, D-tor
	AVLNode(const T& val) 
		: data(val), parent(0), left(0), right(0), leftChildren(0),rightChildren(0), height(1), counter(1) {}
		
	/*AVLNode(const AVLNode& old) 
		: data(old.value), parent(old.parent), left(old.parent), right(old.right), 
		  leftChildren(old.leftChildren), height(old.height), counter(old.counter) {}*/
		  
	~AVLNode() {}
	
	// interface methods
  	void connect(AVLNode* node, const NodeType type) {
  		switch (type) {
  			case LEFT:	left = node;
  						updateHeight();
  						leftChildren = (node == 0) ? 0 : 
  							node->leftChildren + node->rightChildren + node->counter;
  						break;
  							
  			case RIGHT:	right = node;
  						updateHeight();	
						rightChildren = (node == 0) ? 0 : 
							node->leftChildren + node->rightChildren + node->counter;
  						break;							
  							
  			case PARENT:	parent = node;
  							break;
  		}
  	}
  	
  	void disconnect(const NodeType type) {
		switch (type) {
			case LEFT:	leftChildren = 0;
						left = 0;
						updateHeight();
						break;
							
			case RIGHT:	rightChildren = 0;
						right = 0;
						updateHeight();
						break;
							
			case PARENT:	parent = 0;
							break;
		}
  	}
	
  	AVLNode* getTree(const NodeType type) const{
		switch (type) {
			case LEFT:		return left;
			case RIGHT:		return right;
			case PARENT:	return parent;
		}
		return 0;
  	}
  	
	//void addLeftChildren(int num) {leftChildren += num; }
	//void remLeftChildren(int num) {leftChildren -= num; }
	void incCounter() { counter++; }
	void decCounter() { counter--; }
  	int dups() const { return counter; }
  	void setDups(const int new_dups) { counter = new_dups; }
  	
  	int getLeftChildren() const { return leftChildren; }
  	const T& value() const { return data; }
	void setValue(const T& val) { data = val; }

  	bool isLeaf() const { return (left == 0 && right == 0) ? true : false ; }
 	int getHeight() const { return height; }
	void updateHeight() {
		height = 0;
		if (left && right)
			height = (left->height > right->height) ? left->height : right->height;
		else if (left)
			height = left->height;
		else if (right)
			height = right->height;
		height++;
	}
private:
	T data;
	AVLNode* parent;
	AVLNode* left;
	AVLNode* right;
	int leftChildren;
	int rightChildren;
	int height;
	int counter;
};

#endif /*AVL_NODE_H_*/
